# -*- coding: utf8 -*-
#
# Copyright (c) 2009 Matías Ribecky <mail@mribecky.com.ar>
#
# This file is part of twitter-notifications.
# 
# twitter-notifications is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# twitter-notifications is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along
# with twitter-notifications.  If not, see <http://www.gnu.org/licenses/>.

'''Notifies of new updates as they are created.'''

import sys
import time
import argparse
import operator
import logging

import twitternotification.api
import twitternotification.config
from twitternotification.notifier import Notifier

LOGGER = logging.getLogger('twitternotifications.main')
_DEBUG_LEVELS = {'ERROR': logging.ERROR,
                 'WARNING': logging.WARNING,
                 'INFO': logging.INFO,
                 'DEBUG': logging.DEBUG}

def main(argv):
    '''Configure, setup and run the main loop.'''

    try:
        api, notifier, processed_statuses = parse_args(argv)
    except:
        exc_type, exc, tb = sys.exc_info()
        print >>sys.stderr, 'error:', str(exc)
        return 1

    try:
        while True:
            try:
                check_new_statuses(api, notifier, processed_statuses)
                check_new_statuses(api, notifier, processed_statuses)
            except twitternotification.api.NetworkError, e:
                LOGGER.exception('Network error')

            time.sleep(10 * 60)
    except:
        LOGGER.exception('Unexpected error')
        exc_type, exc, tb = sys.exc_info()
        print >>sys.stderr, 'error:', str(exc)
        return 1

    return 0

def parse_args(argv):
    '''Parses the arguments and returns the relevant values.'''

    parser = create_arg_parser()
    args = parser.parse_args(argv[1:])

    if args.debug:
        logging.basicConfig(level=_DEBUG_LEVELS[args.debug])

    cfg = load_config(args)
    if args.debug_config:
        from pprint import pprint
        pprint(cfg)

    config = {'times': cfg['times'],
              'timeout': cfg['timeout']
              }
    LOGGER.debug("Using '%s' notifier" % args.notifier)
    notifier = Notifier.get_plugin(args.notifier)(config)

    if cfg['username']:
        LOGGER.debug("Connecting as '%s'" % cfg['username'])
    else:
        LOGGER.debug("Connecting anonimously")
    if args.debug_api:
        api = twitternotification.api.DummyApi(cfg['username'],
                                               cfg['password'])
    else:
        api = twitternotification.api.Api(cfg['username'], cfg['password'])

    processed_statuses = set()

    return api, notifier, processed_statuses

def create_arg_parser():
    '''Create the argument parser.'''

    parser = argparse.ArgumentParser(description=__doc__)

    notifier_plugins = list(Notifier.plugin_list())
    def more_than_zero(string):
        val = int(string)
        if val > 0:
            return val
        else:
            raise ValueError()

    parser.add_argument('-u', '--username', default=None,
                        help='The username to login')
    parser.add_argument('-p', '--password', default=None,
                        help='The password of the username to login')
    parser.add_argument('-n', '--notifier', default='libnotify',
                        choices=notifier_plugins,
                        help='The notifier plugin, default is libnotify')
    parser.add_argument('-i', '--times', default=None, type=more_than_zero,
                        help='Number of times to show the notification')
    parser.add_argument('-t', '--timeout', default=None, type=int,
                        help='Timeout of the notification')
    parser.add_argument('--debug', default='WARNING', choices=_DEBUG_LEVELS,
                        help='Set the logging level')
    parser.add_argument('--debug-api', default=False, action='store_true',
                        help='Use the dummy Twitter Api to avoid requesting'
                             ' from the server')
    parser.add_argument('--debug-config', action='store_true', default=False,
                        help='Print the loaded configuration')

    return parser

def load_config(args):
    '''Load the config.

    The arguments take precendence over the config file.

    '''

    cfg = twitternotification.config.load()
    if args.username is not None:
        cfg['username'] = args.username
    if args.password is not None:
        cfg['password'] = args.password
    if args.times is not None:
        cfg['times'] = args.times
    if args.timeout is not None:
        cfg['timeout'] = args.timeout

    return cfg

def check_new_statuses(api, notifier, processed_statuses):
    '''Fetches statuses and notifies the new ones.'''

    LOGGER.info("Fetching statuses")
    if processed_statuses:
        statuses = sorted(api.friends_timeline(),
                          key=operator.attrgetter('date'))
        for status in statuses:
            if status.id not in processed_statuses:
                LOGGER.debug("Found new status %s of '%s'" %
                             (status.id, status.user.user_name))
                processed_statuses.add(status.id)
                notifier.notify(status)
    else:
        for status in api.friends_timeline():
            processed_statuses.add(status.id)
        processed_statuses.pop()

    return True # don't unregister callback

if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv))
